home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
awe2-0_1.lha
/
awe2-0.1
/
Src
/
RCS
/
SimulationMultiplexor.cc,v
< prev
next >
Wrap
Text File
|
1989-02-22
|
12KB
|
551 lines
head 3.2;
branch ;
access ;
symbols ;
locks grunwald:3.2; strict;
comment @@;
3.2
date 89.02.20.15.37.25; author grunwald; state Exp;
branches ;
next 3.1;
3.1
date 88.12.20.13.49.15; author grunwald; state Exp;
branches ;
next 1.1;
1.1
date 88.10.30.13.03.23; author grunwald; state Exp;
branches ;
next ;
desc
@@
3.2
log
@Start using Gnu library heaps for schedulers
@
text
@// This may look like C code, but it is really -*- C++ -*-
//
// Copyright (C) 1988 University of Illinois, Urbana, Illinois
//
// written by Dirk Grunwald (grunwald@@cs.uiuc.edu)
//
#include "SimulationMultiplexor.h"
#include "SpinLock.h"
#include "SpinBarrier.h"
#include "SpinFetchAndOp.h"
#include "AwesimeHeap.h"
#include "Thread.h"
#include "TimeSchedulerSplayPQ.h"
#include "ReserveByException.h"
#include <math.h>
SimulationMultiplexor *ThisSimulationMultiplexor;
static SpinBarrier CpuBarrier(0);
//
// The PendingEvents queue is private to each processor
//
static TimeSchedulerPQ *PendingEvents[MaxCpuMultiplexors];
static SpinLock PendingEventsLock[MaxCpuMultiplexors];
double CurrentSimulatedTime = 0.0;
extern int CpuMuxDebugFlag;
SimulationMultiplexor::SimulationMultiplexor(int debug, int spinMax)
: (debug)
{
pNameTemplate = "SimMux";
cpuBarrier = &CpuBarrier;
CpuBarrier.maxLoops(spinMax);
ThisSimulationMultiplexor = this;
ThisCpu = this;
allocateLocalEventStructures(0,1);
sprintf(nameSpace, "[%s-%d] ", pNameTemplate, iYam);
pName = nameSpace;
}
SimulationMultiplexor::~SimulationMultiplexor()
{
}
void
SimulationMultiplexor::allocateLocalEventStructures(int newIYam, int outOf)
{
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << "Allocate SimMux structures for " << newIYam << "\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
PendingEvents[newIYam] = new TimeSchedulerSplayPQ;
myPendingEvents = PendingEvents[newIYam];
myPendingEventsLock = &PendingEventsLock[newIYam];
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << "set CpuBarrier height to " << outOf << "\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
CpuBarrier.height( outOf );
}
void
SimulationMultiplexor::allocateEventStructures(int newIYam, int outOf)
{
allocateLocalEventStructures(newIYam, outOf);
//
// must do this after the local structures get set up so that
// CpuMultiplexors does not increase until all data structures are
// in place, otherwise people may poke at them before they're set up.
//
CpuMultiplexor::allocateEventStructures(newIYam, outOf);
}
void
SimulationMultiplexor::deallocateEventStructures()
{
CpuMultiplexor::deallocateEventStructures();
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << "Deallocate SimMux structures for" << iYam << "\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
PendingEventsLock[0].reserve();
while ( ! myPendingEvents -> empty() ) {
assert( iYam != 0 );
TimeScheduler& item = myPendingEvents -> front();
PendingEvents[0] -> enq( item );
myPendingEvents -> del_front();
}
PendingEventsLock[0].release();
delete myPendingEvents;
myPendingEvents = 0;
PendingEvents[iYam] = 0;
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << "set CpuBarrier height to " << CpuMultiplexors << "\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
CpuBarrier.height(CpuMultiplexors);
}
void
SimulationMultiplexor::warmThePot(int cpus)
{
if ( cpus > MaxCpuMultiplexors ) {
cpus = MaxCpuMultiplexors;
}
CpuBarrier.height(cpus);
CpuMultiplexor::warmThePot(cpus);
int ok = CpuBarrier.rendezvous();
#ifndef NDEBUG
if (! ok ) {
CpuCerrLock.reserve();
cerr << name() << "barrier overrun\n";
CpuCerrLock.release();
}
#endif
}
void
SimulationMultiplexor::stirItAround()
{
while( ! *terminated ) {
CpuMultiplexor::stirItAround();
if (! *terminated ) {
advanceTime();
}
}
}
void
SimulationMultiplexor::coolItDown()
{
CpuBarrier.rendezvous();
CpuMultiplexor::coolItDown();
//
// In case we call rendezvous again
//
CpuBarrier.height(CpuMultiplexors);
}
void
SimulationMultiplexor::addAt(Thread *who, double when)
{
if (when <= CurrentSimulatedTime) {
add(who);
}
else {
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << " add " << who -> name() << " to pending\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
//
// Add them to pending events
//
myPendingEvents->enq( TimeScheduler(who, when) );
}
}
void
SimulationMultiplexor::addWithDelay(Thread *who, double delay)
{
delay += CurrentSimulatedTime;
addAt(who, delay);
}
//
// Advance time. Assumes all other CPUs are idle, so no locking
// on event structures is needed.
//
int
SimulationMultiplexor::advanceTime()
{
//
// If, for some reason, we fail to rendezvous after the timeout,
// click on debug output.
//
int ok = CpuBarrier.rendezvous();
#ifndef NDEBUG
if ( !ok ) {
int oldFlag = CpuMuxDebugFlag;
CpuMuxDebugFlag = 1;
CpuCerrLock.reserve();
cerr << name() << "rendezvous fails, enable debugging\n";
CpuCerrLock.release();
while ( ! CpuBarrier.rendezvous() );
CpuMuxDebugFlag = oldFlag;
CpuCerrLock.reserve();
cerr << name() << "rendezvous resumes, reset debugging\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
//
// Nothing is locked at this point.
//
if (iYam == 0) {
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << "Scan " << CpuMultiplexors << " for pending\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
//
// Find the minimum time over all pending event piles
//
double when = MAXFLOAT;
bool validItem = FALSE;
for (int i = 0; i < CpuMultiplexors; i++ ) {
TimeSchedulerPQ *p = PendingEvents[i];
if ( ! p -> empty() ) {
double hapAt = (p -> front()).time();
if (hapAt < when) {
when = hapAt;
validItem = TRUE;
}
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << i;
cerr << " has one at " << hapAt << "\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
}
#ifndef NDEBUG
else {
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << i << " has nothing\n";
CpuCerrLock.release();
}
}
#endif /* NDEBUG */
}
if ( !validItem ) {
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << " Unable to advance time, exit \n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
*terminated = 1;
}
else {
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << " ADVANCE TIME TO " << when << "\n" ;
CpuCerrLock.release();
}
#endif /* NDEBUG */
assert( CurrentSimulatedTime <= when );
CurrentSimulatedTime = when;
}
}
CpuBarrier.rendezvous();
//
// Now that we know the time of the minimum entry in the
// heap, remove all the events which occur at that time
// or before that time (actually, that is an error).
//
// Each process does its own work to reduce overhead.
// We keep track of how many processes were added to
// the current events queue and then bump the global
// events count by that amout.
//
// This cannot cause race conditions because we only
// use this info in the rendevzous to advance time
// code above, and not all cpus will be there yet
// (i.e. the current cpu is not there)
//
ThreadContainer *c = myCurrentEvents;
int added = 0;
myCurrentEventsLock -> reserve();
TimeSchedulerPQ *p = myPendingEvents;
while ( ! p -> empty() ) {
TimeScheduler &item = p -> front();
if ( item.time() > CurrentSimulatedTime )
break;
addUnlocked( item.thread() );
added++;
p -> del_front();
}
*myCurrentEventsCounter += added;
myCurrentEventsLock -> release();
globalCurrentEventsCounter -> add(added);
#ifndef NDEBUG
if ( CpuMuxDebugFlag ) {
CpuCerrLock.reserve();
cerr << name() << " added " << added << " threads to current";
cerr << ", leaving me " << myPendingEvents -> length() << "\n";
CpuCerrLock.release();
}
#endif
return(added);
}
void
SimulationMultiplexor::await(double when)
{
if (when > CurrentSimulatedTime) {
addAt( currentThread, when );
Thread *next = CpuMultiplexor::remove();
if ( next == 0 ) {
raise( &iveSuspendedException );
} else {
Thread *from = currentThread;
currentThread = next;
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << " switch to " << currentThread -> name() << "\n";
CpuCerrLock.release();
}
#endif /* NDEBUG */
from -> pContext.switchContext ( &(currentThread -> pContext) );
}
}
}
void
SimulationMultiplexor::hold(double holdFor)
{
if (holdFor > 0) {
await( CurrentSimulatedTime + holdFor );
}
}
@
3.1
log
@Steay version
@
text
@d13 3
a15 1
#include "HeapScheduler.h"
d26 2
a27 1
static AwesimeHeap *PendingEvents[MaxCpuMultiplexors];
d62 2
a63 1
PendingEvents[newIYam] = new AwesimeHeap(128);
d107 1
a107 1
while ( ! myPendingEvents -> isEmpty() ) {
d109 3
a111 4
AwesimeHeapItem item;
if (myPendingEvents -> remove(item)) {
PendingEvents[0] -> add( item );
}
d113 1
d189 1
a189 1
myPendingEvents->add( AwesimeHeapItem(when, who) );
d251 3
a253 3
AwesimeHeap *p = PendingEvents[i];
if ( ! p -> isEmpty() ) {
double hapAt = p -> item( p -> minItem() ).key();
d258 1
a320 2
AwesimeHeapItem item;
AwesimeHeap *p = myPendingEvents;
d326 6
a331 9
for (AwesimeHeapIndex index = p -> minItem();
index != AwesimeHeapNull
&& p -> item(index).key() <= CurrentSimulatedTime;
index = p -> minItem() )
{
bool removed = p -> remove(item);
assert( removed );
Thread * who = (Thread *) item.ptr();
addUnlocked( who );
d333 2
a334 1
}
d345 1
a345 1
cerr << ", leaving me " << myPendingEvents -> size() << "\n";
@
1.1
log
@Initial revision
@
text
@d31 1
a31 1
SimulationMultiplexor::SimulationMultiplexor(int debug)
d34 1
a34 1
allocateEventStructures(0);
d36 1
d39 3
d49 1
a49 1
SimulationMultiplexor::allocateEventStructures(int newIYam)
d51 7
a57 3
CpuMultiplexor::allocateEventStructures(newIYam);
sprintf(nameSpace, "[SimulationMultiplexor-%d] ", iYam);
pName = nameSpace;
d59 12
a70 3
PendingEvents[iYam] = new AwesimeHeap(128);
myPendingEvents = PendingEvents[iYam];
myPendingEventsLock = &PendingEventsLock[iYam];
d74 14
d90 1
d93 8
d110 1
a111 1
PendingEventsLock[0].release();
d115 9
d136 8
a143 1
CpuBarrier.rendezvous();
d149 1
a149 2
while( ! *terminated )
{
d151 2
a152 5
#ifndef NDEBUG
if (CpuMuxDebugFlag) {
CpuCerrLock.reserve();
cerr << name() << "Finished with current batch, advance time\n";
CpuCerrLock.release();
a153 2
#endif /*NDEBUG*/
advanceTime();
d203 24
a227 2
CpuBarrier.rendezvous();
d236 1
a236 1
cerr << name() << "rendezvous to advance time\n";
d254 8
d263 9
d275 7
a298 7
//
// Why the second rendezvous?
// If tasks are priority ordered, we want to be able
// to pull them out, order them & then start.
//
// Also, advance time depends on this.
//
d311 1
a311 1
// This canot cause race conditions because we only
d337 1
d343 2
a344 1
cerr << name() << " added " << added << " threads to current\n";
d371 8
@